"""
Session command implementation.

Provides session management capabilities for saving, loading, and
managing exploration sessions and analysis results.
"""

import argparse
import json
import time
from typing import Dict, Any, List, Optional
from pathlib import Path
from datetime import datetime

from ...core.error_handler import CodeMCPError, log_info
from ..base_command import CLICommand


class SessionCommand(CLICommand):
    """Command for managing analysis and exploration sessions."""
    
    def add_parser(self, subparsers) -> argparse.ArgumentParser:
        """Add session command parser."""
        parser = subparsers.add_parser(
            'session',
            help='Manage analysis and exploration sessions',
            description="""
Manage CodeMCP sessions including saving exploration state,
loading previous sessions, and viewing session history.
            """.strip(),
            formatter_class=argparse.RawDescriptionHelpFormatter,
            epilog="""
Examples:
  codemcp session --list
  codemcp session --save my_exploration
  codemcp session --load my_exploration
  codemcp session --info session_123
  codemcp session --delete old_session
            """.strip()
        )
        
        # Action options (mutually exclusive)
        action_group = parser.add_mutually_exclusive_group(required=True)
        action_group.add_argument(
            '--list', '-l',
            action='store_true',
            help='List all saved sessions'
        )
        action_group.add_argument(
            '--save', '-s',
            type=str,
            metavar='NAME',
            help='Save current session with given name'
        )
        action_group.add_argument(
            '--load',
            type=str,
            metavar='NAME',
            help='Load session by name'
        )
        action_group.add_argument(
            '--info', '-i',
            type=str,
            metavar='NAME',
            help='Show detailed information about a session'
        )
        action_group.add_argument(
            '--delete', '-d',
            type=str,
            metavar='NAME',
            help='Delete a saved session'
        )
        action_group.add_argument(
            '--export',
            type=str,
            metavar='NAME',
            help='Export session to file'
        )
        action_group.add_argument(
            '--import',
            type=str,
            metavar='FILE',
            dest='import_file',
            help='Import session from file'
        )
        action_group.add_argument(
            '--cleanup',
            action='store_true',
            help='Clean up old and expired sessions'
        )
        
        # Additional options
        parser.add_argument(
            '--sessions-dir',
            type=str,
            help='Directory to store session files (default: ~/.codemcp/sessions)'
        )
        parser.add_argument(
            '--format',
            choices=['json', 'yaml'],
            default='json',
            help='Session file format (default: json)'
        )
        parser.add_argument(
            '--max-age-days',
            type=int,
            default=30,
            help='Maximum age for sessions during cleanup (default: 30 days)'
        )
        
        return parser
    
    async def execute(self, args: argparse.Namespace) -> int:
        """Execute the session command."""
        try:
            # Initialize session manager
            sessions_dir = self._get_sessions_directory(args)
            session_manager = SessionManager(sessions_dir, args.format)
            
            # Execute the requested action
            if args.list:
                return await self._list_sessions(session_manager, args)
            elif args.save:
                return await self._save_session(session_manager, args.save, args)
            elif args.load:
                return await self._load_session(session_manager, args.load, args)
            elif args.info:
                return await self._show_session_info(session_manager, args.info, args)
            elif args.delete:
                return await self._delete_session(session_manager, args.delete, args)
            elif args.export:
                return await self._export_session(session_manager, args.export, args)
            elif args.import_file:
                return await self._import_session(session_manager, args.import_file, args)
            elif args.cleanup:
                return await self._cleanup_sessions(session_manager, args)
            
            return 0
            
        except CodeMCPError as e:
            self.printer.print_error(f"Session error: {e.message}")
            return 1
        except Exception as e:
            self.printer.print_error(f"Unexpected error: {e}")
            return 1
    
    def _get_sessions_directory(self, args: argparse.Namespace) -> Path:
        """Get the sessions directory path."""
        if args.sessions_dir:
            return Path(args.sessions_dir)
        
        # Default sessions directory
        default_dir = Path.home() / ".codemcp" / "sessions"
        default_dir.mkdir(parents=True, exist_ok=True)
        return default_dir
    
    async def _list_sessions(self, session_manager: 'SessionManager', args: argparse.Namespace) -> int:
        """List all saved sessions."""
        try:
            sessions = session_manager.list_sessions()
            
            if not sessions:
                self.printer.print_info("No saved sessions found")
                return 0
            
            self.printer.print_header("Saved Sessions", level=1)
            
            # Sort sessions by last modified (newest first)
            sessions.sort(key=lambda s: s.get('last_modified', ''), reverse=True)
            
            # Display sessions in table format
            headers = ["Name", "Type", "Files", "Last Modified", "Size"]
            widths = [20, 12, 8, 20, 10]
            
            self.printer.print_table_header(headers, widths)
            
            for i, session in enumerate(sessions):
                name = session.get('name', 'unknown')[:18]
                session_type = session.get('type', 'unknown')[:10]
                file_count = str(session.get('file_count', 0))
                last_modified = session.get('last_modified', 'unknown')
                if last_modified != 'unknown':
                    try:
                        dt = datetime.fromisoformat(last_modified.replace('Z', '+00:00'))
                        last_modified = dt.strftime('%Y-%m-%d %H:%M')
                    except:
                        pass
                last_modified = last_modified[:18]
                
                size = session.get('size_kb', 0)
                size_str = f"{size}KB" if size > 0 else "unknown"
                
                values = [name, session_type, file_count, last_modified, size_str]
                self.printer.print_table_row(values, widths, alternate=(i % 2 == 1))
            
            self.printer.print_table_footer(widths)
            
            self.printer.print_info(f"\nTotal sessions: {len(sessions)}")
            
        except Exception as e:
            self.printer.print_error(f"Failed to list sessions: {e}")
            return 1
        
        return 0
    
    async def _save_session(self, session_manager: 'SessionManager', name: str, args: argparse.Namespace) -> int:
        """Save current session."""
        try:
            # For now, create a mock session since we don't have active session state
            # In a real implementation, this would save the current exploration/analysis state
            
            session_data = {
                'name': name,
                'type': 'exploration',
                'created_at': datetime.utcnow().isoformat(),
                'last_modified': datetime.utcnow().isoformat(),
                'version': '1.0.0',
                'metadata': {
                    'cli_version': '1.0.0',
                    'platform': 'linux',
                    'user': 'user'
                },
                'configuration': {
                    'max_depth': self.config.server.max_tree_depth,
                    'cache_enabled': self.config.cache.enabled,
                    'llm_provider': self.config.llm.provider
                },
                'exploration_data': {
                    'current_file': 'example.py',
                    'current_function': 'main',
                    'navigation_stack': ['main', 'process_data'],
                    'nodes_visited': 5,
                    'max_depth_reached': 3,
                    'exploration_path': [
                        {'name': 'main', 'file': 'example.py', 'line': 1, 'timestamp': time.time()},
                        {'name': 'process_data', 'file': 'example.py', 'line': 15, 'timestamp': time.time()}
                    ]
                },
                'analysis_results': {
                    'call_trees': [],
                    'statistics': {
                        'total_files': 1,
                        'total_nodes': 5,
                        'analysis_duration': 120.5
                    }
                }
            }
            
            session_manager.save_session(name, session_data)
            
            self.printer.print_success(f"Session saved: {name}")
            self.printer.print_info(f"Location: {session_manager.sessions_dir / f'{name}.{args.format}'}")
            
        except Exception as e:
            self.printer.print_error(f"Failed to save session: {e}")
            return 1
        
        return 0
    
    async def _load_session(self, session_manager: 'SessionManager', name: str, args: argparse.Namespace) -> int:
        """Load a saved session."""
        try:
            session_data = session_manager.load_session(name)
            
            if not session_data:
                self.printer.print_error(f"Session not found: {name}")
                return 1
            
            self.printer.print_success(f"Session loaded: {name}")
            
            # Display session information
            self.formatter.print_session_info(session_data)
            
            # In a real implementation, this would restore the session state
            self.printer.print_info("\nSession state would be restored for interactive exploration")
            
        except Exception as e:
            self.printer.print_error(f"Failed to load session: {e}")
            return 1
        
        return 0
    
    async def _show_session_info(self, session_manager: 'SessionManager', name: str, args: argparse.Namespace) -> int:
        """Show detailed information about a session."""
        try:
            session_data = session_manager.load_session(name)
            
            if not session_data:
                self.printer.print_error(f"Session not found: {name}")
                return 1
            
            self.printer.print_header(f"Session Information: {name}", level=1)
            
            # Basic information
            basic_info = {
                'Name': session_data.get('name', 'unknown'),
                'Type': session_data.get('type', 'unknown'),
                'Created': session_data.get('created_at', 'unknown'),
                'Last Modified': session_data.get('last_modified', 'unknown'),
                'Version': session_data.get('version', 'unknown')
            }
            
            self.printer.print_header("Basic Information", level=2)
            for key, value in basic_info.items():
                self.printer.print_key_value(key, value)
            
            # Configuration
            if 'configuration' in session_data:
                self.printer.print_header("Configuration", level=2)
                config = session_data['configuration']
                for key, value in config.items():
                    self.printer.print_key_value(key.replace('_', ' ').title(), value)
            
            # Exploration data
            if 'exploration_data' in session_data:
                self.printer.print_header("Exploration Data", level=2)
                exploration = session_data['exploration_data']
                
                exploration_info = {
                    'Current File': exploration.get('current_file', 'unknown'),
                    'Current Function': exploration.get('current_function', 'unknown'),
                    'Nodes Visited': exploration.get('nodes_visited', 0),
                    'Max Depth': exploration.get('max_depth_reached', 0),
                    'Navigation Stack': ' → '.join(exploration.get('navigation_stack', []))
                }
                
                for key, value in exploration_info.items():
                    self.printer.print_key_value(key, value)
                
                # Exploration path
                if exploration.get('exploration_path'):
                    self.printer.print_header("Exploration Path", level=3)
                    for step in exploration['exploration_path']:
                        step_info = f"{step['name']} ({step['file']}:{step['line']})"
                        timestamp = datetime.fromtimestamp(step['timestamp']).strftime('%H:%M:%S')
                        self.printer.print_list_item(f"{step_info} at {timestamp}")
            
            # Analysis results
            if 'analysis_results' in session_data:
                results = session_data['analysis_results']
                if 'statistics' in results:
                    self.printer.print_header("Analysis Statistics", level=2)
                    stats = results['statistics']
                    for key, value in stats.items():
                        self.printer.print_key_value(key.replace('_', ' ').title(), value)
            
        except Exception as e:
            self.printer.print_error(f"Failed to show session info: {e}")
            return 1
        
        return 0
    
    async def _delete_session(self, session_manager: 'SessionManager', name: str, args: argparse.Namespace) -> int:
        """Delete a saved session."""
        try:
            if not session_manager.session_exists(name):
                self.printer.print_error(f"Session not found: {name}")
                return 1
            
            # Confirm deletion
            confirm = input(f"Delete session '{name}'? (y/N): ").strip().lower()
            if confirm not in ['y', 'yes']:
                self.printer.print_info("Deletion cancelled")
                return 0
            
            session_manager.delete_session(name)
            self.printer.print_success(f"Session deleted: {name}")
            
        except Exception as e:
            self.printer.print_error(f"Failed to delete session: {e}")
            return 1
        
        return 0
    
    async def _export_session(self, session_manager: 'SessionManager', name: str, args: argparse.Namespace) -> int:
        """Export session to file."""
        try:
            session_data = session_manager.load_session(name)
            
            if not session_data:
                self.printer.print_error(f"Session not found: {name}")
                return 1
            
            # Determine export file name
            export_file = Path(f"{name}_export.{args.format}")
            
            # Save to export file
            with open(export_file, 'w', encoding='utf-8') as f:
                if args.format == 'json':
                    json.dump(session_data, f, indent=2, default=str)
                else:  # yaml
                    import yaml
                    yaml.dump(session_data, f, default_flow_style=False, indent=2)
            
            self.printer.print_success(f"Session exported: {export_file}")
            
        except Exception as e:
            self.printer.print_error(f"Failed to export session: {e}")
            return 1
        
        return 0
    
    async def _import_session(self, session_manager: 'SessionManager', import_file: str, args: argparse.Namespace) -> int:
        """Import session from file."""
        try:
            import_path = Path(import_file)
            
            if not import_path.exists():
                self.printer.print_error(f"Import file not found: {import_file}")
                return 1
            
            # Load session data from file
            with open(import_path, 'r', encoding='utf-8') as f:
                if import_path.suffix.lower() == '.json':
                    session_data = json.load(f)
                else:  # yaml
                    import yaml
                    session_data = yaml.safe_load(f)
            
            # Get session name
            session_name = session_data.get('name', import_path.stem)
            
            # Check if session already exists
            if session_manager.session_exists(session_name):
                overwrite = input(f"Session '{session_name}' already exists. Overwrite? (y/N): ").strip().lower()
                if overwrite not in ['y', 'yes']:
                    self.printer.print_info("Import cancelled")
                    return 0
            
            # Import session
            session_manager.save_session(session_name, session_data)
            
            self.printer.print_success(f"Session imported: {session_name}")
            
        except Exception as e:
            self.printer.print_error(f"Failed to import session: {e}")
            return 1
        
        return 0
    
    async def _cleanup_sessions(self, session_manager: 'SessionManager', args: argparse.Namespace) -> int:
        """Clean up old and expired sessions."""
        try:
            max_age_days = args.max_age_days
            cutoff_time = datetime.utcnow().timestamp() - (max_age_days * 24 * 3600)
            
            sessions = session_manager.list_sessions()
            old_sessions = []
            
            for session in sessions:
                last_modified = session.get('last_modified')
                if last_modified:
                    try:
                        dt = datetime.fromisoformat(last_modified.replace('Z', '+00:00'))
                        if dt.timestamp() < cutoff_time:
                            old_sessions.append(session['name'])
                    except:
                        # If we can't parse the date, consider it old
                        old_sessions.append(session['name'])
            
            if not old_sessions:
                self.printer.print_info(f"No sessions older than {max_age_days} days found")
                return 0
            
            self.printer.print_info(f"Found {len(old_sessions)} sessions older than {max_age_days} days:")
            for session_name in old_sessions:
                self.printer.print_list_item(session_name)
            
            confirm = input(f"\nDelete {len(old_sessions)} old sessions? (y/N): ").strip().lower()
            if confirm not in ['y', 'yes']:
                self.printer.print_info("Cleanup cancelled")
                return 0
            
            # Delete old sessions
            deleted_count = 0
            for session_name in old_sessions:
                try:
                    session_manager.delete_session(session_name)
                    deleted_count += 1
                except Exception as e:
                    self.printer.print_warning(f"Failed to delete {session_name}: {e}")
            
            self.printer.print_success(f"Cleanup completed: {deleted_count} sessions deleted")
            
        except Exception as e:
            self.printer.print_error(f"Failed to cleanup sessions: {e}")
            return 1
        
        return 0


class SessionManager:
    """Manages session storage and retrieval."""
    
    def __init__(self, sessions_dir: Path, format: str = 'json'):
        self.sessions_dir = sessions_dir
        self.format = format
        self.sessions_dir.mkdir(parents=True, exist_ok=True)
    
    def save_session(self, name: str, session_data: Dict[str, Any]):
        """Save session data to file."""
        session_file = self.sessions_dir / f"{name}.{self.format}"
        
        with open(session_file, 'w', encoding='utf-8') as f:
            if self.format == 'json':
                json.dump(session_data, f, indent=2, default=str)
            else:  # yaml
                import yaml
                yaml.dump(session_data, f, default_flow_style=False, indent=2)
    
    def load_session(self, name: str) -> Optional[Dict[str, Any]]:
        """Load session data from file."""
        session_file = self.sessions_dir / f"{name}.{self.format}"
        
        if not session_file.exists():
            return None
        
        with open(session_file, 'r', encoding='utf-8') as f:
            if self.format == 'json':
                return json.load(f)
            else:  # yaml
                import yaml
                return yaml.safe_load(f)
    
    def session_exists(self, name: str) -> bool:
        """Check if session exists."""
        session_file = self.sessions_dir / f"{name}.{self.format}"
        return session_file.exists()
    
    def delete_session(self, name: str):
        """Delete a session file."""
        session_file = self.sessions_dir / f"{name}.{self.format}"
        if session_file.exists():
            session_file.unlink()
    
    def list_sessions(self) -> List[Dict[str, Any]]:
        """List all available sessions."""
        sessions = []
        
        for session_file in self.sessions_dir.glob(f"*.{self.format}"):
            try:
                session_data = self.load_session(session_file.stem)
                if session_data:
                    # Add file metadata
                    stat = session_file.stat()
                    session_data['file_size'] = stat.st_size
                    session_data['size_kb'] = round(stat.st_size / 1024, 1)
                    session_data['file_count'] = len(session_data.get('analysis_results', {}).get('call_trees', []))
                    
                    sessions.append(session_data)
            except Exception:
                # Skip corrupted session files
                continue
        
        return sessions